﻿//  -------------------- iSharePoint -------------------- //
// 
//  Company:	IT Complex, LLC
//  Project:	Smart.Common
//  File name:	RuleChecker.cs
//  Developer:	Solomatov Igor
//  Created:	15.04.2012
// 
//  -------------------- iSharePoint -------------------- //

using System;

namespace Smart.Common.Rules
{
	/// <summary>
	/// Rule checker
	/// </summary>
	public abstract class RuleChecker
	{
		/// <summary>
		/// Rule context
		/// </summary>
		public RulesCtx Ctx { get; set; }

		/// <summary>
		/// Rule checker (creates new Instance using rule and update values)
		/// </summary>
		/// <param name="ctx">Rule context</param>
		protected RuleChecker(RulesCtx ctx)
		{
			Ctx = ctx;
		}

		/// <summary>
		/// Check rule's condition
		/// </summary>
		/// <returns>true, if rule's condition is fulfilled</returns>
		public virtual bool CheckRule<TRuleType>(TRuleType rule)
			where TRuleType : class, IRule
		{
			if (rule == null)
				throw new ArgumentNullException("rule");

			return CheckCondition(rule.Condition);
		}

		/// <summary>
		/// Check rule's condition, checks whole condition hierarchy 
		/// </summary>
		/// <returns>true, if rule's condition is fulfilled</returns>
		public virtual bool CheckCondition<TRuleConditionType>(TRuleConditionType condition)
			where TRuleConditionType : class, IRuleCondition
		{
			if (condition == null) throw new ArgumentNullException("condition");

			bool fullfilled;

			if (condition.IsSingle())
			{
				fullfilled = IsConditionFullfilled(condition);
			}
			else
			{
				fullfilled = true;

				foreach (var child in condition.Children)
				{
					fullfilled = CheckCondition(child);

					if ((condition.Operator == ComparisonOperator.And) ^ fullfilled)
						return fullfilled;
				}
			}

			return fullfilled;
		}

		/// <summary>
		/// Check rule's condition, checks only single condition
		/// </summary>
		/// <typeparam name="TRuleConditionType">Type of rule's condition</typeparam>
		/// <param name="condition">Rule's condition</param>
		/// <returns>Tested whether the condition</returns>
		public abstract bool IsConditionFullfilled<TRuleConditionType>(TRuleConditionType condition)
			where TRuleConditionType : IRuleCondition;
	}
}